package top.byteio.common.core.utils;

import jakarta.servlet.http.HttpServletRequest;
import lombok.experimental.UtilityClass;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.regex.Pattern;

/**
 * IP工具类
 * 包含获取请求IP、IP地理位置、IP验证、IP类型判断等功能
 * @author lerryxia
 */
@UtilityClass
public class IPAddressUtils {

    // 可能包含真实IP的请求头列表
    private static final String[] IP_HEADER_CANDIDATES = {
            "X-Forwarded-For",
            "Proxy-Client-IP",
            "WL-Proxy-Client-IP",
            "HTTP_X_FORWARDED_FOR",
            "HTTP_X_FORWARDED",
            "HTTP_X_CLUSTER_CLIENT_IP",
            "HTTP_CLIENT_IP",
            "HTTP_FORWARDED_FOR",
            "HTTP_FORWARDED",
            "HTTP_VIA",
            "REMOTE_ADDR"
    };

    // IPv4地址正则表达式
    private static final Pattern IPV4_PATTERN = Pattern.compile(
            "^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$"
    );

    // IPv6地址正则表达式
    private static final Pattern IPV6_PATTERN = Pattern.compile(
            "^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^([0-9a-fA-F]{1,4}:){1,7}:$|^([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}$|^([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}$|^([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}$|^([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}$|^([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}$|^[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})$|^:((:[0-9a-fA-F]{1,4}){1,7}|:)$"
    );

    /**
     * 获取客户端真实IP地址
     * 考虑了各种代理服务器的情况
     * @param request HttpServletRequest对象
     * @return 客户端真实IP地址
     */
    public static String getRequestIp(HttpServletRequest request) {
        if (request == null) {
            return "unknown";
        }

        // 遍历所有可能的IP头信息
        for (String header : IP_HEADER_CANDIDATES) {
            String ip = request.getHeader(header);
            if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
                // X-Forwarded-For可能包含多个IP，取第一个
                if (ip.contains(",")) {
                    ip = ip.split(",")[0].trim();
                }
                return ip;
            }
        }

        // 如果没有获取到，则使用getRemoteAddr()
        String ip = request.getRemoteAddr();

        // 处理本地地址
        if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
            try {
                // 获取本机真实IP
                InetAddress localHost = InetAddress.getLocalHost();
                ip = localHost.getHostAddress();
            } catch (UnknownHostException e) {
                // 忽略异常，返回默认值
            }
        }

        return ip;
    }

    /**
     * 通过第三方API获取IP地址对应的地理位置
     * 使用ip-api.com的免费接口，支持中文
     * @param ip IP地址
     * @return 地理位置信息，格式如"国家,地区,城市"
     */
    public static String getIpLocation(String ip) {
        // 本地IP直接返回
        if (ip == null || ip.isEmpty() || "127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
            return "本地网络";
        }

        String url = "http://ip-api.com/json/" + ip + "?lang=zh-CN";
        StringBuilder result = new StringBuilder();
        BufferedReader in = null;

        try {
            URI uri = URI.create(url);
            URL realUrl = uri.toURL();
            HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(5000);
            connection.setReadTimeout(5000);

            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }

            // 解析JSON响应
            return parseIpApiResponse(result.toString());
        } catch (MalformedURLException e) {
            return "获取地理位置失败：无效的URL";
        } catch (IOException e) {
            return "获取地理位置失败：网络错误";
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                // 忽略关闭异常
            }
        }
    }

    /**
     * 解析ip-api.com的响应结果
     * @param jsonResponse JSON响应字符串
     * @return 格式化的地理位置信息
     */
    private static String parseIpApiResponse(String jsonResponse) {
        // 简单解析，实际项目中建议使用Jackson或Gson等JSON库
        if (jsonResponse == null || jsonResponse.isEmpty()) {
            return "未知位置";
        }

        // 检查请求是否成功
        if (jsonResponse.contains("\"status\":\"success\"")) {
            String country = extractValue(jsonResponse, "country");
            String regionName = extractValue(jsonResponse, "regionName");
            String city = extractValue(jsonResponse, "city");

            // 组合结果
            StringBuilder location = new StringBuilder();
            if (country != null && !country.isEmpty()) {
                location.append(country);
            }
            if (regionName != null && !regionName.isEmpty()) {
                if (location.length() > 0) {
                    location.append(",");
                }
                location.append(regionName);
            }
            if (city != null && !city.isEmpty()) {
                if (location.length() > 0) {
                    location.append(",");
                }
                location.append(city);
            }

            return location.length() > 0 ? location.toString() : "未知位置";
        } else {
            String message = extractValue(jsonResponse, "message");
            return "获取失败：" + (message != null ? message : "未知错误");
        }
    }

    /**
     * 从JSON字符串中提取指定字段的值
     * 简单实现，实际项目中建议使用JSON库
     * @param json JSON字符串
     * @param field 字段名
     * @return 字段值
     */
    private static String extractValue(String json, String field) {
        String searchStr = "\"" + field + "\":";
        int index = json.indexOf(searchStr);
        if (index == -1) {
            return null;
        }

        int start = index + searchStr.length();
        // 跳过空格
        while (start < json.length() && Character.isWhitespace(json.charAt(start))) {
            start++;
        }

        if (start >= json.length()) {
            return null;
        }

        // 判断值是否为字符串（用双引号括起来）
        if (json.charAt(start) == '"') {
            start++;
            int end = json.indexOf("\"", start);
            if (end != -1) {
                return json.substring(start, end);
            }
        }

        // 处理非字符串值（如数字、布尔等）
        int end = start;
        while (end < json.length() && ",}]".indexOf(json.charAt(end)) == -1) {
            end++;
        }

        if (end > start) {
            return json.substring(start, end).trim();
        }

        return null;
    }

    /**
     * 获取当前请求的IP地址对应的地理位置
     * @param request HttpServletRequest对象
     * @return 地理位置信息
     */
    public static String getRequestIpLocation(HttpServletRequest request) {
        String ip = getRequestIp(request);
        return getIpLocation(ip);
    }

    /**
     * 验证是否为有效的IPv4地址
     * @param ip 待验证的IP地址
     * @return 有效返回true，否则返回false
     */
    public static boolean isIpv4(String ip) {
        if (ip == null || ip.isEmpty()) {
            return false;
        }
        return IPV4_PATTERN.matcher(ip).matches();
    }

    /**
     * 验证是否为有效的IPv6地址
     * @param ip 待验证的IP地址
     * @return 有效返回true，否则返回false
     */
    public static boolean isIpv6(String ip) {
        if (ip == null || ip.isEmpty()) {
            return false;
        }
        return IPV6_PATTERN.matcher(ip).matches();
    }

    /**
     * 判断IP地址类型
     * @param ip 待判断的IP地址
     * @return "IPv4"、"IPv6"或"Invalid"
     */
    public static String getIpType(String ip) {
        if (isIpv4(ip)) {
            return "IPv4";
        } else if (isIpv6(ip)) {
            return "IPv6";
        } else {
            return "Invalid";
        }
    }

    /**
     * 判断是否为内网IP（仅支持IPv4）
     * 内网IP范围：
     * - 10.0.0.0 ~ 10.255.255.255
     * - 172.16.0.0 ~ 172.31.255.255
     * - 192.168.0.0 ~ 192.168.255.255
     * @param ip IPv4地址
     * @return 是内网IP返回true，否则返回false
     */
    public static boolean isInternalIpv4(String ip) {
        if (!isIpv4(ip)) {
            return false;
        }

        long ipLong = ipToLong(ip);
        // 10.0.0.0 ~ 10.255.255.255
        boolean is10Net = (ipLong >= ipToLong("10.0.0.0")) && (ipLong <= ipToLong("10.255.255.255"));
        // 172.16.0.0 ~ 172.31.255.255
        boolean is172Net = (ipLong >= ipToLong("172.16.0.0")) && (ipLong <= ipToLong("172.31.255.255"));
        // 192.168.0.0 ~ 192.168.255.255
        boolean is192Net = (ipLong >= ipToLong("192.168.0.0")) && (ipLong <= ipToLong("192.168.255.255"));

        return is10Net || is172Net || is192Net;
    }

    /**
     * 将IPv4地址转换为长整数
     * @param ip IPv4地址
     * @return 对应的长整数
     */
    public static long ipToLong(String ip) {
        if (!isIpv4(ip)) {
            throw new IllegalArgumentException("Invalid IPv4 address: " + ip);
        }

        String[] parts = ip.split("\\.");
        long result = 0;
        for (int i = 0; i < 4; i++) {
            result |= Long.parseLong(parts[i]) << (24 - i * 8);
        }
        return result & 0xFFFFFFFFL;
    }

    /**
     * 将长整数转换为IPv4地址
     * @param ipLong 长整数
     * @return 对应的IPv4地址
     */
    public static String longToIp(long ipLong) {
        // 确保值在IPv4范围内
        ipLong = ipLong & 0xFFFFFFFFL;
        return ((ipLong >> 24) & 0xFF) + "." +
                ((ipLong >> 16) & 0xFF) + "." +
                ((ipLong >> 8) & 0xFF) + "." +
                (ipLong & 0xFF);
    }

    /**
     * 获取本机所有IP地址（不包含回环地址）
     * @return 本机IP地址列表
     */
    public static List<String> getLocalIps() {
        List<String> ips = new ArrayList<>();
        try {
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            while (interfaces.hasMoreElements()) {
                NetworkInterface ni = interfaces.nextElement();
                Enumeration<InetAddress> addresses = ni.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress addr = addresses.nextElement();
                    // 排除回环地址和IPv6本地链路地址
                    if (!addr.isLoopbackAddress() &&
                            !(addr instanceof Inet6Address && addr.isLinkLocalAddress())) {
                        ips.add(addr.getHostAddress());
                    }
                }
            }
        } catch (SocketException e) {
            // 忽略异常
        }
        return ips;
    }

    /**
     * 检查IP地址是否在指定的CIDR范围内（仅支持IPv4）
     * @param ip 待检查的IPv4地址
     * @param cidr CIDR表示法，如"192.168.1.0/24"
     * @return 在范围内返回true，否则返回false
     */
    public static boolean isIpInCidr(String ip, String cidr) {
        if (!isIpv4(ip) || cidr == null || !cidr.contains("/")) {
            return false;
        }

        String[] cidrParts = cidr.split("/");
        if (cidrParts.length != 2) {
            return false;
        }

        String networkIp = cidrParts[0];
        if (!isIpv4(networkIp)) {
            return false;
        }

        int prefixLength;
        try {
            prefixLength = Integer.parseInt(cidrParts[1]);
            if (prefixLength < 0 || prefixLength > 32) {
                return false;
            }
        } catch (NumberFormatException e) {
            return false;
        }

        long ipLong = ipToLong(ip);
        long networkLong = ipToLong(networkIp);
        long mask = (0xFFFFFFFFL << (32 - prefixLength)) & 0xFFFFFFFFL;

        return (ipLong & mask) == (networkLong & mask);
    }
}

